﻿namespace AlgoHero.Modelo
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;

    public class Cancion
    {
        #region Atributos

        private string nombre;
        private Partitura partitura;
        private double tiempoDeCompas;
        private MapeoDeTeclas mapeo;
        private MapaTemporal mapaTemporal;

        #endregion Atributos

        #region Constructores

        public Cancion(string nombre, Partitura partitura, double tiempoDeCompas, MapeoDeTeclas mapeo)
        {
            /* Precondiciones: tiempoDeCompas debe ser un número entero positivo mayor a 0.
             * Postcondición: lanza ArgumentException si tiempoDeCompas es inválido.
             */
            if (tiempoDeCompas <= 0)
            {
                throw new ArgumentException("El tiempo de compás debe ser positivo.");
            }

            this.nombre = nombre;
            this.partitura = partitura;
            this.tiempoDeCompas = tiempoDeCompas;
            this.mapeo = mapeo;
            this.CalcularMapaTemporal();                        
        }

        #endregion

        #region Propiedades

        public string Nombre
        {
            get { return nombre; }
        }
        
        public Partitura Partitura
        {
            get { return partitura; }
        }
        
        public double TiempoDeCompas
        {
            get { return tiempoDeCompas; }
        }
        
        public MapeoDeTeclas Mapeo
        {
            get { return mapeo; }
            set { mapeo = value; }
        }

        public MapaTemporal MapaTemporal
        {
            get { return mapaTemporal; }
        }

        public double Duracion  //Obtiene la duracion total de la cancion, en segundos.
        {
            get { return this.mapaTemporal.TiempoTotal; }
        }

        #endregion

        #region Métodos

        public void Play()
        {
            throw new NotImplementedException();
        }

        private void CalcularMapaTemporal()
        {
            this.mapaTemporal = new MapaTemporal(this);
        }

        public IList<Tecla> ObtenerTeclasAPresionar(double tiempoDeReproduccion)
        {
            /* Obtiene las teclas a presionar para un instante de reproduccion de la cancion.
             * Precondiciones: El tiempo debe ser no negativo y no mayor a la duracion total de la cancion.
             * Postcondiciones: Lanza ArgumentException si tiempo es negativo. Lanza TiempoInvalidoException 
             * si tiempoDeReproduccion es mayor que la duracion de la cancion.
             */

            IList<Tecla> teclasAPresionar = this.mapaTemporal.ObtenerTeclasAPresionar(tiempoDeReproduccion);

            return teclasAPresionar;
        }

        public Acorde ObtenerAcordePara(double tiempoDeReproduccion)
        {
            /* Devuelve el acorde correspondiente al tiempo de reproduccion dado.
             * Precondiciones: El tiempo debe ser no negativo y no mayor a la duracion total de la cancion.
             * Postcondiciones: Lanza ArgumentException si tiempo es negativo. Lanza TiempoInvalidoException 
             * si tiempoDeReproduccion es mayor que la duracion de la cancion.
             */

            Acorde acorde = this.mapaTemporal.ObtenerAcordePara(tiempoDeReproduccion);

            return acorde;
        }

        public bool EsValida(IList<Tecla> teclasPresionadas, double tiempoDeReproduccion)
        {
            /* Devuelve TRUE si la combinacion de teclas es valida para el instante tiempoDeReproduccion.
             * Precondiciones: El tiempo debe ser no negativo y no mayor a la duracion total de la cancion.
             * Postcondiciones: Lanza ArgumentException si tiempo es negativo. Lanza TiempoInvalidoException 
             * si tiempoDeReproduccion es mayor que la duracion de la cancion.
             */

            IList<Tecla> teclasCorrectas = this.ObtenerTeclasAPresionar(tiempoDeReproduccion);

            foreach (Tecla tecla in teclasPresionadas)
            {
                if (!teclasCorrectas.Contains(tecla))// esto no contempla si al usuario le faltaron teclas por presionar
                {
                    return false;
                }
            }

            return true;
        }
               

        #endregion
        

    }
}
